/**
 ******************************************************************************
 * @file           : bsp_dht11.c
 * @brief          : DHT11 Temperature and Humidity Sensor Driver (STM32H7xx)
 ******************************************************************************
 * @attention
 *
 * DHT11温湿度传感器驱动实现文件
 * 单总线通信协议
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "./Devices/DHT11/bsp_dht11.h"
#include "./Devices/DHT11/bsp_dht11_config.h"

/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define DHT11_BIT_0_TIME    26      /*!< 0位持续时间（us） */
#define DHT11_BIT_1_TIME    70      /*!< 1位持续时间（us） */

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static volatile uint8_t sg_dht11_initialized = 0;  /*!< 初始化标志 */
static volatile uint32_t sg_last_read_time = 0;    /*!< 上次读取时间 */

/* Private function prototypes -----------------------------------------------*/
static void dht11_gpio_init(void);
static void dht11_gpio_deinit(void);
static void dht11_set_output(void);
static void dht11_set_input(void);
static uint8_t dht11_read_bit(void);
static uint8_t dht11_read_byte(void);
static DHT11_Error_e dht11_read_raw(DHT11_RawData_t *raw_data);
static uint8_t dht11_check_sum(DHT11_RawData_t *raw_data);

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       DHT11 GPIO初始化
 *
 * @param       无
 *
 * @retval      无
 */
static void dht11_gpio_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    DHT11_GPIO_CLK_ENABLE();

    GPIO_InitStruct.Pin = DHT11_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStruct);

    /* 初始状态：高电平 */
    HAL_GPIO_WritePin(DHT11_GPIO_PORT, DHT11_GPIO_PIN, GPIO_PIN_SET);
}

/**
 * @brief       DHT11 GPIO反初始化
 *
 * @param       无
 *
 * @retval      无
 */
static void dht11_gpio_deinit(void)
{
    HAL_GPIO_DeInit(DHT11_GPIO_PORT, DHT11_GPIO_PIN);
}

/**
 * @brief       设置DHT11为输出模式
 *
 * @param       无
 *
 * @retval      无
 */
static void dht11_set_output(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    GPIO_InitStruct.Pin = DHT11_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStruct);
}

/**
 * @brief       设置DHT11为输入模式
 *
 * @param       无
 *
 * @retval      无
 */
static void dht11_set_input(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    GPIO_InitStruct.Pin = DHT11_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStruct);
}

/**
 * @brief       读取一个比特
 *
 * @param       无
 *
 * @retval      uint8_t - 比特值（0或1）
 */
static uint8_t dht11_read_bit(void)
{
    uint32_t timeout = DHT11_TIMEOUT_US;

    /* 等待低电平 */
    while(HAL_GPIO_ReadPin(DHT11_GPIO_PORT, DHT11_GPIO_PIN) == GPIO_PIN_SET && timeout--);
    if(timeout == 0) return 0;

    timeout = DHT11_TIMEOUT_US;

    /* 等待高电平 */
    while(HAL_GPIO_ReadPin(DHT11_GPIO_PORT, DHT11_GPIO_PIN) == GPIO_PIN_RESET && timeout--);
    if(timeout == 0) return 0;

    /* 延迟30us，判断电平 */
    for(int i = 0; i < 30; i++) __NOP();

    if(HAL_GPIO_ReadPin(DHT11_GPIO_PORT, DHT11_GPIO_PIN) == GPIO_PIN_SET)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

/**
 * @brief       读取一个字节
 *
 * @param       无
 *
 * @retval      uint8_t - 字节值
 */
static uint8_t dht11_read_byte(void)
{
    uint8_t byte = 0;

    for(int i = 0; i < 8; i++)
    {
        byte <<= 1;
        byte |= dht11_read_bit();
    }

    return byte;
}

/**
 * @brief       读取DHT11原始数据
 *
 * @param[out]  raw_data - 原始数据指针
 *
 * @retval      DHT11_Error_e - 错误码
 */
static DHT11_Error_e dht11_read_raw(DHT11_RawData_t *raw_data)
{
    uint32_t timeout;

    if(raw_data == NULL)
    {
        return DHT11_ERROR_PARAM;
    }

    /* 主机发送开始信号 */
    dht11_set_output();
    HAL_GPIO_WritePin(DHT11_GPIO_PORT, DHT11_GPIO_PIN, GPIO_PIN_RESET);
    HAL_Delay(18);  /* 至少18ms */
    HAL_GPIO_WritePin(DHT11_GPIO_PORT, DHT11_GPIO_PIN, GPIO_PIN_SET);

    /* 等待DHT11响应 */
    dht11_set_input();
    timeout = DHT11_TIMEOUT_US * 10;
    while(HAL_GPIO_ReadPin(DHT11_GPIO_PORT, DHT11_GPIO_PIN) == GPIO_PIN_SET && timeout--);
    if(timeout == 0) return DHT11_ERROR_TIMEOUT;

    timeout = DHT11_TIMEOUT_US * 10;
    while(HAL_GPIO_ReadPin(DHT11_GPIO_PORT, DHT11_GPIO_PIN) == GPIO_PIN_RESET && timeout--);
    if(timeout == 0) return DHT11_ERROR_TIMEOUT;

    /* 读取5个字节 */
    raw_data->humidity_int = dht11_read_byte();
    raw_data->humidity_dec = dht11_read_byte();
    raw_data->temperature_int = dht11_read_byte();
    raw_data->temperature_dec = dht11_read_byte();
    raw_data->checksum = dht11_read_byte();

    return DHT11_OK;
}

/**
 * @brief       校验和检查
 *
 * @param[in]   raw_data - 原始数据指针
 *
 * @retval      uint8_t - 1=正确, 0=错误
 */
static uint8_t dht11_check_sum(DHT11_RawData_t *raw_data)
{
    uint8_t sum = raw_data->humidity_int + raw_data->humidity_dec +
                  raw_data->temperature_int + raw_data->temperature_dec;

    return (sum == raw_data->checksum) ? 1 : 0;
}

/* Public functions ----------------------------------------------------------*/

DHT11_Error_e dht11_init(void)
{
    if(sg_dht11_initialized)
    {
        return DHT11_OK;
    }

    dht11_gpio_init();
    sg_dht11_initialized = 1;
    sg_last_read_time = 0;

    log_i("DHT11 initialized");
    return DHT11_OK;
}

void dht11_deinit(void)
{
    if(!sg_dht11_initialized)
    {
        return;
    }

    dht11_gpio_deinit();
    sg_dht11_initialized = 0;

    log_i("DHT11 deinitialized");
}

DHT11_Error_e dht11_read(DHT11_Data_t *data)
{
    DHT11_RawData_t raw_data;
    DHT11_Error_e ret;
    uint32_t current_time;

    if(!sg_dht11_initialized)
    {
        log_e("DHT11 not initialized");
        return DHT11_ERROR_NOT_INIT;
    }

    if(data == NULL)
    {
        log_e("Invalid pointer");
        return DHT11_ERROR_PARAM;
    }

    /* 检查最小采样周期 */
    current_time = HAL_GetTick();
    if((current_time - sg_last_read_time) < DHT11_MIN_INTERVAL_MS)
    {
        log_w("Sampling interval too short");
        return DHT11_ERROR_TIMEOUT;
    }

    /* 读取原始数据 */
    ret = dht11_read_raw(&raw_data);
    if(ret != DHT11_OK)
    {
        log_e("Failed to read raw data");
        return ret;
    }

    /* 校验数据 */
    if(!dht11_check_sum(&raw_data))
    {
        log_e("Checksum error");
        return DHT11_ERROR_CHECKSUM;
    }

    /* 转换数据 */
    data->humidity = raw_data.humidity_int + (raw_data.humidity_dec / 10.0f);
    data->temperature = raw_data.temperature_int + (raw_data.temperature_dec / 10.0f);

    sg_last_read_time = current_time;

    log_d("Temperature: %.1f°C, Humidity: %.1f%%RH", data->temperature, data->humidity);
    return DHT11_OK;
}

DHT11_Error_e dht11_read_temperature(float *temperature)
{
    DHT11_Data_t data;
    DHT11_Error_e ret;

    if(temperature == NULL)
    {
        return DHT11_ERROR_PARAM;
    }

    ret = dht11_read(&data);
    if(ret == DHT11_OK)
    {
        *temperature = data.temperature;
    }

    return ret;
}

DHT11_Error_e dht11_read_humidity(float *humidity)
{
    DHT11_Data_t data;
    DHT11_Error_e ret;

    if(humidity == NULL)
    {
        return DHT11_ERROR_PARAM;
    }

    ret = dht11_read(&data);
    if(ret == DHT11_OK)
    {
        *humidity = data.humidity;
    }

    return ret;
}

void dht11_print_status(void)
{
    DHT11_Data_t data;

    log_i("=== DHT11 Status ===");
    log_i("Initialized: %s", sg_dht11_initialized ? "Yes" : "No");

    if(dht11_read(&data) == DHT11_OK)
    {
        log_i("Temperature: %.1f°C", data.temperature);
        log_i("Humidity: %.1f%%RH", data.humidity);
    }
    else
    {
        log_e("Failed to read DHT11");
    }
}
